"""
图像处理模块 - 专注于纯图像处理功能

此模块包含图像二值化、形态学操作等基础图像处理功能。
遵循单一职责原则，只处理图像本身的变换，不涉及业务逻辑。
"""
import cv2
import numpy as np
from typing import Optional


class ImageProcessor:
    """
    图像处理器类，专注于纯图像处理功能
    
    功能包括：
    - 图像二值化（自适应、Otsu、简单阈值）
    - 形态学操作
    - 图像预处理
    """
    
    def __init__(
        self,
        binarization_method: str = 'adaptive',
        adaptive_block_size: int = 15,
        adaptive_c: int = 5,
        otsu_threshold: int = 0,
        binary_threshold: int = 127
    ):
        """
        初始化图像处理器
        
        参数:
            binarization_method: 二值化方法 ('adaptive', 'otsu', 'simple')
            adaptive_block_size: 自适应二值化块大小
            adaptive_c: 自适应二值化常数
            otsu_threshold: Otsu二值化阈值 (0表示自动)
            binary_threshold: 简单二值化阈值
        """
        self.binarization_method = binarization_method
        self.adaptive_block_size = adaptive_block_size
        self.adaptive_c = adaptive_c
        self.otsu_threshold = otsu_threshold
        self.binary_threshold = binary_threshold
        
    def binarize_image(self, image: np.ndarray) -> np.ndarray:
        """
        对图像进行二值化处理
        
        参数:
            image: 输入图像
            
        返回:
            np.ndarray: 二值化图像
        """
        if image is None or image.size == 0:
            return np.array([])
        
        # 转为灰度图
        if len(image.shape) == 3:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        else:
            gray = image.copy()
            
        # 平滑处理以减少噪声
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
            
        # 根据选择的方法进行二值化
        if self.binarization_method == 'adaptive':
            binary = self._adaptive_threshold(blurred)
        elif self.binarization_method == 'otsu':
            binary = self._otsu_threshold(blurred)
        else:
            binary = self._simple_threshold(blurred)
        
        # 形态学处理以连接临近的文字或图形元素
        binary = self._morphological_close(binary)
            
        return binary
    
    def _adaptive_threshold(self, gray_image: np.ndarray) -> np.ndarray:
        """自适应二值化"""
        block_size = self.adaptive_block_size
        if block_size % 2 == 0:
            block_size += 1  # 确保块大小为奇数
            
        return cv2.adaptiveThreshold(
            gray_image,
            255,
            cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
            cv2.THRESH_BINARY_INV,
            block_size,
            self.adaptive_c
        )
    
    def _otsu_threshold(self, gray_image: np.ndarray) -> np.ndarray:
        """Otsu阈值二值化"""
        if self.otsu_threshold <= 0:
            _, binary = cv2.threshold(
                gray_image, 0, 255, 
                cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU
            )
        else:
            _, binary = cv2.threshold(
                gray_image, self.otsu_threshold, 255, 
                cv2.THRESH_BINARY_INV
            )
        return binary
    
    def _simple_threshold(self, gray_image: np.ndarray) -> np.ndarray:
        """简单二值化"""
        _, binary = cv2.threshold(
            gray_image, self.binary_threshold, 255, 
            cv2.THRESH_BINARY_INV
        )
        return binary
    
    def _morphological_close(self, binary_image: np.ndarray) -> np.ndarray:
        """形态学闭运算"""
        kernel = np.ones((3, 3), np.uint8)
        return cv2.morphologyEx(binary_image, cv2.MORPH_CLOSE, kernel)
    
    def dilate(self, image: np.ndarray, kernel_size: int = 3, iterations: int = 1) -> np.ndarray:
        """
        图像膨胀操作
        
        参数:
            image: 输入图像
            kernel_size: 核大小
            iterations: 迭代次数
            
        返回:
            np.ndarray: 膨胀后的图像
        """
        kernel = np.ones((kernel_size, kernel_size), np.uint8)
        return cv2.dilate(image, kernel, iterations=iterations)
    
    def erode(self, image: np.ndarray, kernel_size: int = 3, iterations: int = 1) -> np.ndarray:
        """
        图像腐蚀操作
        
        参数:
            image: 输入图像
            kernel_size: 核大小
            iterations: 迭代次数
            
        返回:
            np.ndarray: 腐蚀后的图像
        """
        kernel = np.ones((kernel_size, kernel_size), np.uint8)
        return cv2.erode(image, kernel, iterations=iterations)
    
    def gaussian_blur(self, image: np.ndarray, kernel_size: int = 5, sigma: float = 0) -> np.ndarray:
        """
        高斯模糊
        
        参数:
            image: 输入图像
            kernel_size: 核大小
            sigma: 标准差
            
        返回:
            np.ndarray: 模糊后的图像
        """
        return cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma)
    
    def to_grayscale(self, image: np.ndarray) -> np.ndarray:
        """
        转换为灰度图
        
        参数:
            image: 输入图像
            
        返回:
            np.ndarray: 灰度图像
        """
        if len(image.shape) == 3:
            return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        return image.copy()
    
    def resize(self, image: np.ndarray, width: int, height: int, 
               interpolation: int = cv2.INTER_LINEAR) -> np.ndarray:
        """
        调整图像大小
        
        参数:
            image: 输入图像
            width: 目标宽度
            height: 目标高度
            interpolation: 插值方法
            
        返回:
            np.ndarray: 调整大小后的图像
        """
        return cv2.resize(image, (width, height), interpolation=interpolation)
